﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Up2Link.Core;

namespace Up2Link.Client
{
    /// <summary>
    /// 客户端类
    /// </summary>
    /// <typeparam name="T">消息格式</typeparam>
    public class CClient<T>
        where T : IMessage , new()
    {
        /// <summary>
        /// 被封装的CTcpConnection对象
        /// </summary>
        private CTcpConnection tc = null;

        /// <summary>
        /// 客户端状态标记
        /// </summary>
        private Boolean clientOn = false;

        /// <summary>
        /// 客户端逻辑线程
        /// </summary>
        private Thread update = null;

        /// <summary>
        /// 构造函数
        /// 创建客户端逻辑线程
        /// </summary>
        public CClient()
        {
            update = new Thread(new ThreadStart(Update));
        }

        /// <summary>
        /// 启动客户端
        /// </summary>
        /// <param name="address">服务器的ip地址</param>
        /// <param name="port">服务器的端口号</param>
        /// <returns>如果启动过程中发生异常或错误，函数返回false，否则返回true</returns>
        /// <example>client.Start("127.0.0.1", 1234);</example>
        public Boolean Start(String address, Int32 port)
        {
            //创建Tcp套接字对象，并尝试连接服务器
            TcpClient client = null;
            try
            {
                client = new TcpClient();
                client.Connect(IPAddress.Parse(address), port);
            }
            catch (Exception e)
            {
                //如果捕捉到异常，则关闭套接字，并返回false
                if (client != null)
                {
                    client.Close();
                }
                //System.Console.WriteLine(e.StackTrace);
                return false;
            }

            //如果一切顺利，则将Tcp套接字传递给CTcpConnection的构造函数
            tc = new CTcpConnection(client);
            clientOn = true;

            //启动客户端逻辑线程
            update.Start();

            //返回true
            return true;
        }

        /// <summary>
        /// 返回客户端接收到的消息
        /// </summary>
        /// <returns>返回队列中的第一条消息，如果队列为空则返回null</returns>
        public T Receive()
        {
            Byte[] data = tc.Receive();
            if (data != null)
            {
                T tempT = new T();
                tempT.Decode(data);
                return tempT;
            }

            //返回类型T的默认值
            //如果T为引用类型，则等同于return null
            //如果T为数值类型，则等同于return 0
            //如果T为结构，则结构内的每一个成员都会被赋予默认值
            return default(T);
        }

        /// <summary>
        /// 发送一条消息
        /// </summary>
        /// <param name="msg">待发送的消息</param>
        public void Send(T msg)
        {
            tc.Send(msg.Encode());
        }        

        /// <summary>
        /// 返回客户端的运行状态
        /// </summary>
        /// <returns>客户端的运行状态</returns>
        public Boolean isClientOn()
        {
            return clientOn;
        }

        /// <summary>
        /// 关闭客户端
        /// </summary>
        public void Close()
        {
            clientOn = false;
            update.Join();
            tc.Close();
        }

        /// <summary>
        /// 客户端逻辑函数
        /// </summary>
        private void Update()
        {
            //循环条件为客户端正在运行
            while (clientOn)
            {
                //调用被封装的CTcpConnection对象的update函数
                tc.Update();

                //如果函数调用后Tcp连接被关闭，则关闭客户端
                if (!tc.IsClientOn())
                {
                    clientOn = false;
                }

                Thread.Sleep(100);
            }
        }
    }
}
